package com.wxw.BaseLibrary.db;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.wxw.BaseLibrary.element.JsonObject;
import com.wxw.BaseLibrary.element.JsonProperty;
import com.wxw.BaseLibrary.element.JsonPropertyType;
import com.wxw.BaseLibrary.infa.IDatabaseInitAgent;
import com.wxw.BaseLibrary.infa.IDbObject;
import com.wxw.BaseLibrary.infa.IGeneralEventCallback;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by david on 14-3-12.
 */
public class DBTool extends SQLiteOpenHelper {
    public static final String TAG = "DBTool";
    private static DBTool dbTool;
    public static Context mContext = null;
    public static IDatabaseInitAgent DatabaseInitAgent = null;
    public static boolean isChange = false;
    public static int DATABASE_VERSION = 1;
    public static String DATABASE_NAME = "";

    private IGeneralEventCallback onMessageGeneralListener = null;

    private DBTool(Context context, int version) {
        super(context, DATABASE_NAME, null, version);
    }

    public synchronized static DBTool getInstance(Context context){
        if (isChange) {
            isChange = false;
            dbTool = new DBTool(context, DATABASE_VERSION);
        } else {
            if (dbTool == null) {
                dbTool = new DBTool(context, DATABASE_VERSION);
            }
        }
        return dbTool;
    }

    public synchronized static DBTool getInstance(){
        if (mContext == null || DATABASE_VERSION < 0) {
            return null;
        }
        return getInstance(mContext);
    }

    public void setOnMessageGeneralListener(IGeneralEventCallback onMessageGeneralListener) {
        this.onMessageGeneralListener = onMessageGeneralListener;
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        List<String> sqlStrings = new ArrayList<String>();
        sqlStrings.add("Create Table IF NOT EXISTS SubmitTable(ID INTEGER PRIMARY KEY AUTOINCREMENT, "
                + "MessageName text, RequestContent text,ResponseContent text, RequestService text, "
                + "RequestMethod text, RequestParamName text, MessageType int, MessageKey text, Forever int, "
                + "CountDown int, Pause int, "
                + "httpMethod int, Status int, LastUpdate text)");
        for (String s : sqlStrings) {
            execSQL(sqLiteDatabase, s);
        }
        if (DatabaseInitAgent != null) {
            DatabaseInitAgent.initDatabase(sqLiteDatabase);
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i2) {
        if (i2 > i && DatabaseInitAgent != null) {
            DatabaseInitAgent.updateDatabase(sqLiteDatabase, i2);
        }
    }

    public synchronized void execSQL(SQLiteDatabase db, String sql){
        try {
            db.execSQL(sql);
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            triggerEvent("DBTool.execSQL Exception:"+e.getMessage());
        }
    }

    public synchronized void execSQL(String sql) {
        try {
            SQLiteDatabase db = getReadableDatabase();
            db.execSQL(sql);
        } catch (Exception e) {
            Log.e(TAG, e.getMessage());
            triggerEvent("DBTool.execSQL Exception:"+e.getMessage());
        }
    }

    public synchronized Cursor query(String sql) {
        Cursor cursor = null;
        try {
            SQLiteDatabase db = getReadableDatabase();
            cursor = db.rawQuery(sql, null);
        } catch (Exception e) {
            Log.e(TAG,"DBTool.query:" + e.getMessage());
            triggerEvent("DBTool.query Exception:"+e.getMessage());
        }
        return cursor;
    }

    public synchronized <T> List<T> query(String sql, Type type) {
        return convertToObjects(query(sql), type);
    }

    public synchronized long insert(String tableName, ContentValues values) {
        long i = 0;
        try {
            SQLiteDatabase db = getReadableDatabase();
            i = db.insert(tableName, null, values);
        } catch (Exception e) {
            Log.e(TAG,"DBTool.insert:" + e.getMessage());
            triggerEvent("DBTool.insert Exception:"+e.getMessage());
        }
        return i;
    }

    public synchronized int update(String tableName, ContentValues values, String where, String[] whereval) {
        int i = 0;
        try {
            SQLiteDatabase db = getReadableDatabase();
            i = db.update(tableName, values, where, whereval);
        } catch (Exception e) {
            Log.e(TAG,"DBTool.update:" + e.getMessage());
            triggerEvent("DBTool.update Exception:"+e.getMessage());
        }
        return i;
    }

    public synchronized int delete(String tableName, String where, String[] whereval) {
        int i = 0;
        try {
            SQLiteDatabase db = getReadableDatabase();
            i = db.delete(tableName, where, whereval);
        } catch (Exception e) {
            Log.e(TAG,"DBTool.delete:" + e.getMessage());
            triggerEvent("DBTool.delete Exception:"+e.getMessage());
        }
        return i;
    }

    public static String toJsonString(Cursor cursor) {
        if (cursor == null) {
            return "[]";
        }
        String[] colNames = cursor.getColumnNames();
        JsonProperty jsonArray = new JsonProperty();
        while (cursor.moveToNext()) {
            JsonProperty jsonItem = jsonArray.add(new JsonObject());
            for (int i=0;i<colNames.length;i++) {
                Object val = null;
                switch (cursor.getType(i)){
                    case Cursor.FIELD_TYPE_INTEGER:
                        val = cursor.getInt(i);
                        break;
                    case Cursor.FIELD_TYPE_FLOAT:
                        val = cursor.getFloat(i);
                        break;
                    case Cursor.FIELD_TYPE_STRING:
                        val = cursor.getString(i).replace("\"", "'");
                        break;
                    case Cursor.FIELD_TYPE_BLOB:
                        val = cursor.getBlob(i);
                        break;
                    default:
                        break;
                }
                jsonItem.setProperty(colNames[i], new JsonProperty(val));
            }
        }
        if (jsonArray.getType()== JsonPropertyType.Null) {
            return "[]";
        } else {
            return jsonArray.toString();
        }
    }

    public static <T> List<T> convertToObjects(Cursor cursor, Type type) {
        if (cursor==null) {
            return  new ArrayList<T>();
        }
        return new Gson().fromJson(toJsonString(cursor), type);
    }

    public static <T extends IDbObject> List<T> convertCursorToList(Cursor cursor, Class<T> c){
        List<T> tList = new ArrayList<T>();
        try {
            T t = c.newInstance();
            while ((t = (T)t.full(cursor)) != null) {
                tList.add(t);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (cursor != null) {
            cursor.close();
        }
        return tList;
    }

    private void triggerEvent(String msg) {
        if (onMessageGeneralListener!=null) {
            onMessageGeneralListener.finished(this, msg);
        }
    }
}
